
package v2store

import (
	"fmt"
	"path"
	"strings"
	"sync"

	"go.etcd.io/etcd/server/v3/etcdserver/api/v2error"
)

// EventHistory是对eventQueue的一层封装，
type EventHistory struct {
	Queue      eventQueue	// 用来存储Event实例的eventQueue实例。
	StartIndex uint64	// 当前EventHistory实例中记录的第一个Event实例的Modifiedlndex字段值。
	// 当前EventHistory实例中记录的最后一个Event实例的Modifiedindex字段值，
	// 从而可知，EventHistory只记录了从Startindex～Lastindex之间的Event。
	LastIndex  uint64
	// 在添加或读取Event实例时，都需要通过该锁进行同步。
	rwl        sync.RWMutex
}

func newEventHistory(capacity int) *EventHistory {
	return &EventHistory{
		Queue: eventQueue{
			Capacity: capacity,
			Events:   make([]*Event, capacity),
		},
	}
}

// EventHistory.addEvent（）方法提供了添加新Event实例的功能
func (eh *EventHistory) addEvent(e *Event) *Event {
	eh.rwl.Lock()	// 通过rwl锁进行同步
	defer eh.rwl.Unlock()
	eh.Queue.insert(e)	// 添加Event买例
	eh.LastIndex = e.Index()	// 更新StartIndex字段和LastIndex字段
	eh.StartIndex = eh.Queue.Events[eh.Queue.Front].Index()
	return e
}

// EventHistory.scan（）方法会从index参数指定的位置开始查找EventHistory中是否记录了参数key指定节点对应的Event实例，
func (eh *EventHistory) scan(key string, recursive bool, index uint64) (*Event, *v2error.Error) {
	// 加锁和解锁的相关逻辑
	eh.rwl.RLock()
	defer eh.rwl.RUnlock()
	// 检测工ndex参数是否合法（即位于Startindex～LastIndex之间）（
	if index < eh.StartIndex {
		return nil,
			v2error.NewError(v2error.EcodeEventIndexCleared,
				fmt.Sprintf("the requested history has been cleared [%v/%v]",
					eh.StartIndex, index), 0)
	}
	if index > eh.LastIndex { // 未来索引
		return nil, nil
	}
	// 首先将index参数转换成eventQueue.Events的下标
	offset := index - eh.StartIndex
	i := (eh.Queue.Front + int(offset)) % eh.Queue.Capacity

	for {	// 边历index之后的Event实例
		e := eh.Queue.Events[i]
		if !e.Refresh {	// 过滤拌Refresh类型的修改操作
			ok := e.Node.Key == key	// 根据Key匹配Event实例
			// key可能是个目录，根据recursive参数决定是否查找其子节点对应的Event
			if recursive {
				nkey := path.Clean(key)
				if nkey[len(nkey)-1] != '/' {
					nkey = nkey + "/"
				}

				ok = ok || strings.HasPrefix(e.Node.Key, nkey)
			}
			// 针对Delete、Expire等操作的处理，比较的是Event.PrevNode
			if (e.Action == Delete || e.Action == Expire) && e.PrevNode != nil && e.PrevNode.Dir {
				ok = ok || strings.HasPrefix(key, e.PrevNode.Key)
			}

			if ok {
				return e, nil
			}
		}

		i = (i + 1) % eh.Queue.Capacity
		// 整个EventHistory中不存在与参数key匹配的Event实例
		if i == eh.Queue.Back {
			return nil, nil
		}
	}
}

// 克隆将受停止世界锁
// 不需要获取内部锁
func (eh *EventHistory) clone() *EventHistory {
	clonedQueue := eventQueue{
		Capacity: eh.Queue.Capacity,
		Events:   make([]*Event, eh.Queue.Capacity),
		Size:     eh.Queue.Size,
		Front:    eh.Queue.Front,
		Back:     eh.Queue.Back,
	}

	copy(clonedQueue.Events, eh.Queue.Events)
	return &EventHistory{
		StartIndex: eh.StartIndex,
		Queue:      clonedQueue,
		LastIndex:  eh.LastIndex,
	}

}
